﻿using System;
using UniRx;
using UniRx.Operators;

/// <summary>
/// T触发器
/// </summary>
internal class ToggleTriggerObservable<TSource, TControl> : OperatorObservableBase<TSource>
{
    private readonly IObservable<TSource> m_Source;
    private readonly IObservable<TControl> m_Control;

    public ToggleTriggerObservable(IObservable<TSource> source, IObservable<TControl> control)
        : base(source.IsRequiredSubscribeOnCurrentThread())
    {
        m_Source = source;
        m_Control = control;
    }

    protected override IDisposable SubscribeCore(IObserver<TSource> observer, IDisposable cancel)
    {
        return new SourceObserver(this, observer, cancel).Run();
    }

    // 输入信号处理
    internal class SourceObserver : OperatorObserverBase<TSource, TSource>
    {
        private readonly ToggleTriggerObservable<TSource, TControl> m_Parent;
        private object m_Gate = new object();
        private bool m_IsToggleOn = true;

        public SourceObserver(ToggleTriggerObservable<TSource, TControl> parent, IObserver<TSource> observer, IDisposable cancel) : base(observer, cancel)
        {
            m_Parent = parent;
        }

        public IDisposable Run()
        {
            var sourceSubscription = m_Parent.m_Source.Subscribe(this);
            var controlSubscription = m_Parent.m_Control.Subscribe(new ControlObserver(this));

            return StableCompositeDisposable.Create(sourceSubscription, controlSubscription);
        }

        public override void OnNext(TSource value)
        {
            lock (m_Gate)
            {
                if (m_IsToggleOn)
                {
                    observer.OnNext(value);
                }
            }
        }

        public override void OnError(Exception error)
        {
            lock (m_Gate)
            {
                try { observer.OnError(error); } finally { Dispose(); }
            }
        }

        public override void OnCompleted()
        {
            lock (m_Gate)
            {
                try { observer.OnCompleted(); } finally { Dispose(); }
            }
        }

        // 控制脉冲处理
        internal class ControlObserver : IObserver<TControl>
        {
            private readonly SourceObserver parent;

            public ControlObserver(SourceObserver parent)
            {
                this.parent = parent;
            }

            public void OnNext(TControl value)
            {
                lock (parent.m_Gate)
                {
                    parent.m_IsToggleOn = !parent.m_IsToggleOn;
                }
            }

            public void OnError(Exception error)
            {
            }

            public void OnCompleted()
            {
            }
        }
    }
}